package concurrentpractice;

import java.util.concurrent.LinkedBlockingQueue;
import org.junit.Test;

public class BlockingQueueSolution {

  private enum Printer {
    NUMBER, LETTER
  }

  /**
   * 共享一个queue，根据peek和poll的不同来实现
   */
  @Test
  public void verifyBlockingShareQueue() throws InterruptedException {
    final LinkedBlockingQueue<Printer> queue = new LinkedBlockingQueue<>();
    queue.offer(Printer.NUMBER);

    Thread numberPrintThread = new Thread(() -> {
      for (int i = 1; i < 52; i = i + 2) {
        while (Printer.NUMBER != queue.peek()) {
          // waiting numberPrint be enabled.
        }
        for (int j = 0; j < 2; j++) {
          System.out.print(i + j);
        }
        queue.offer(Printer.LETTER);
        queue.poll();
      }
    });
    Thread letterPrintThread = new Thread(() -> {
      for (char i = 'A'; i <= 'Z'; i++) {
        while (Printer.LETTER != queue.peek()) {
          // waiting letterPrint be enabled.
        }
        System.out.print(i);
        queue.offer(Printer.NUMBER);
        queue.poll();
      }
    });

    numberPrintThread.start();
    letterPrintThread.start();

    numberPrintThread.join();
    letterPrintThread.join();
  }

  /**
   * 两个queue，利用take()会自动阻塞来实现
   */
  @Test
  public void verifyBlockingQueue() throws InterruptedException {
    final LinkedBlockingQueue<Printer> numberPrintQueue = new LinkedBlockingQueue<>();
    final LinkedBlockingQueue<Printer> letterPrintQueue = new LinkedBlockingQueue<>();
    numberPrintQueue.offer(Printer.NUMBER);

    Thread numberPrintThread = new Thread(() -> {
      for (int i = 1; i < 52; i = i + 2) {
        try {
          numberPrintQueue.take();
          for (int j = 0; j < 2; j++) {
            System.out.print(i + j);
          }
          letterPrintQueue.offer(Printer.LETTER);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    });
    Thread letterPrintThread = new Thread(() -> {
      for (char i = 'A'; i <= 'Z'; i++) {
        try {
          letterPrintQueue.take();
          System.out.print(i);
          numberPrintQueue.offer(Printer.NUMBER);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    });

    numberPrintThread.start();
    letterPrintThread.start();

    numberPrintThread.join();
    letterPrintThread.join();
  }
}
